#include "stdafx.h"
#include "primitive_datatypes.h"
#include "Enums.h"
#include "Desc.h"
#include "RenderEngine.h"
#include "D3D9RenderEngine.h"
#include "GameEngine.h"

//##########################################################
CGameEngine::CGameEngine(void){	
	this->_GameEngineState = EGameEngineState::NotInitialised;
}
//##########################################################?
CGameEngine::~CGameEngine(void){
}
//##########################################################?
void CGameEngine::Init(GameEngineInitDesc& InitDesc){	
	this->_AppName		= InitDesc.AppName;
	this->_FullScreen	= InitDesc.FullScreen;
	this->_ScreenWidth	= InitDesc.Width;
	this->_ScreenHeight	= InitDesc.Height;
	this->_AppInst		= GetModuleHandle(NULL);
	this->InitWindow();
	this->InitRenderEngine(InitDesc.RenderEngine);
}
//##########################################################?
Int CGameEngine::Run(void){
	// Load the conten befor run
	this->Load();
	
	MSG msg;
	ZeroMemory(&msg,sizeof(msg));
	while(msg.message != WM_QUIT){
		if(PeekMessage(&msg, NULL, 0, 0,PM_REMOVE)){	
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}else{
			// per frame stuff
			this->Update(this->GetDeltaTime());
			this->_RenderEngine->Render();
		}
	}

	return (Int) msg.wParam;
}
//##########################################################
void CGameEngine::Load(void){
}
//##########################################################
void CGameEngine::InitRenderEngine(Enum RenderEngine){
	switch (RenderEngine){
		case ERenderEngine::OpenGL4:
		case ERenderEngine::D3D10:
		case ERenderEngine::D3D9:{
			this->_RenderEngine = new CD3D9RenderEngine();
			RenderEngineInitDesc desc;
			desc.FullScreen		= this->_FullScreen;
			desc.Height			= this->_ScreenHeight;
			desc.Width			= this->_ScreenWidth;
			desc.WindowInstance	= this->_MainWinInst;
			this->_RenderEngine->Init(desc);
			break;}
		default:
			assert(false);
			break;
	}
}
//##########################################################
void CGameEngine::InitWindow(void){
	assert(this->_GameEngineState == EGameEngineState::NotInitialised);
	
	WNDCLASSEX wcex;	
	wcex.cbSize = sizeof(WNDCLASSEX);
	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= this->_AppInst;
	wcex.hIcon			= 0;
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= 0;
	wcex.lpszClassName	= this->_AppName.c_str();
	wcex.hIconSm		= 0;
	RegisterClassEx(&wcex);
	
	if(this->_FullScreen){
		this->_MainWinInst = CreateWindow(
			this->_AppName.c_str(),
			this->_AppName.c_str(), 
			WS_EX_TOPMOST | WS_POPUP | WS_VISIBLE,
			CW_USEDEFAULT,CW_USEDEFAULT, 
			this->_ScreenWidth, 
			this->_ScreenHeight,
			NULL, NULL, 
			this->_AppInst,
			NULL);
		
	}else{
		this->_MainWinInst = CreateWindow(
			this->_AppName.c_str(),
			this->_AppName.c_str(),
			WS_OVERLAPPEDWINDOW,
			CW_USEDEFAULT,CW_USEDEFAULT,
			this->_ScreenWidth, 
			this->_ScreenHeight, 
			NULL, NULL,
			this->_AppInst,
			NULL);
	}
	
	assert(this->_MainWinInst);
		
	ShowWindow(this->_MainWinInst ,SW_SHOW);
	UpdateWindow(this->_MainWinInst);
	
	return;
}
//##########################################################
void CGameEngine::Update(Number dt){
}
//##########################################################
//##########################################################
//##########################################################
Number CGameEngine::GetDeltaTime(void){
	static __int64 i64LastCounter;
	
	if (i64LastCounter == 0){
		QueryPerformanceCounter((LARGE_INTEGER*)&i64LastCounter);
	}

	__int64 i64Counter;
	BOOL b;
	b = QueryPerformanceCounter((LARGE_INTEGER*)&i64Counter);
	assert(b && "QueryPerformanceCounter failed");
	
	__int64 i64CounterFrq;
	b = QueryPerformanceFrequency((LARGE_INTEGER*)&i64CounterFrq);
	
	assert(b && "QueryPerformanceCounter failed");
	
	Number fDeltaTime = (Number)(((NumberD)(i64Counter - i64LastCounter)) / ((NumberD)i64CounterFrq));
	
	i64LastCounter = i64Counter;
	
	return fDeltaTime;
}
//##########################################################
LRESULT CALLBACK CGameEngine::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
	switch (message){	
		case WM_DESTROY:
			PostQuitMessage(0);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}
//##########################################################?